package router

import (
	"errors"
	"fmt"
	"os"
	"strings"
	"time"

	"gitee.com/liukexing/isrn/model"
)

type BoradcastHandller func(data *model.Trans) error

const ()

var (
	BoradcastAction BoradcastHandller
)

type PathInfo struct {
	Path   string
	Length int
	Update time.Time
}

type NodeInfo struct {
	Peerid  string
	ReqId   string
	RouList []PathInfo
	Create  time.Time
	Key     RemoteCyprto
}

func BoradcastCheck(data *model.Trans, sender *ConnectInfo) error {
	//transid
	if data.TransId != sender.NodeId {
		return errors.New("transid Check Failed")
	}
	//Trans
	trans := data.PackInfo.Trans
	if len(trans) == 0 || trans[0] != nodeid {
		return errors.New("Trans Check Failed")
	}
	//Trans Sign
	transok, err := sender.RCyprto.Verify(data.Data, data.Sign)
	if err != nil {
		return err
	}
	if !transok {
		return errors.New("Trans Sign Check Failed")
	}

	return nil
}

func BoradcastController(data *model.Trans, isEncrypt bool, sender *ConnectInfo) error {
	err := BoradcastCheck(data, sender)
	if err != nil {
		return err
	}

	//Pack Boradcast
	if data.PackInfo.Receiver != nodeid {
		trans := data.PackInfo.Trans
		if len(trans) > 10 {
			return errors.New("Trans Nodes Too many")
		}
		conns := strings.Join(trans, ",")
		for _, v := range connectlist {
			if v.Active && !strings.Contains(conns, v.NodeId) {
				BoradcastTrans(data, v)
				conns = conns + "," + v.NodeId
			}
		}
		l := listenlist.Front()
		for l != nil {
			v := l.Value.(*ConnectInfo)
			if v.Active && !strings.Contains(conns, v.NodeId) {
				BoradcastTrans(data, v)
				conns = conns + "," + v.NodeId
			}
			l = l.Next()
		}
		return nil
	}

	return BoradcastAction(data)
}

func BoradcastTrans(data *model.Trans, conn *ConnectInfo) {
	data.TransId = nodeid

	conns := conn.NodeId + "," + strings.Join(data.PackInfo.Trans, ",")
	data.PackInfo.Trans = strings.Split(conns, ",")

	sn, err := conn.RCyprto.Sign(data.Data)
	if err != nil {
		fmt.Fprintln(os.Stdout, "Trans Error:%s", err.Error())
	}
	data.Sign = sn

	msg, err := getTransByte(data, true, &conn.RCyprto)
	if err != nil {
		fmt.Fprintln(os.Stdout, "Trans Error:%s", err.Error())
	}
	conn.SendMsg(msg)
	return
}

func BoradcastSend(peerid string, info *model.BoradcastInfo, conn *ConnectInfo) error {
	data, err := info.GetByte()
	if err != nil {
		return err
	}

	s, err := conn.RCyprto.Sign(data)
	if err != nil {
		return err
	}
	trans := &model.Trans{}
	trans.CreatPackInfo(data, s, nodeid, peerid)
	trans.PackInfo.Trans = strings.Split(conn.NodeId+","+nodeid, ",")
	trans.PackInfo.Lengh = len(data)
	trans.Sign = s
	trans.PackType = model.Boradcast

	msg, err := getTransByte(trans, true, &conn.RCyprto)
	if err != nil {
		return err
	}
	conn.SendMsg(msg)
	return nil
}

func BoradcastAllConn(peerid string) {
	if peerid == nodeid {
		fmt.Println("Boradcast to self is not enabled")
		return
	}
	conns := nodeid

	data := &model.BoradcastInfo{
		NodeId: nodeid,
		Sign:   model.GetRandomString(12),
	}
	for _, v := range connectlist {
		if v.Active && !strings.Contains(conns, v.NodeId) {
			err := BoradcastSend(peerid, data, v)
			if err != nil {
				fmt.Println("BoradcastAllConn:", err)
			}
			conns = conns + "," + v.NodeId
		}
	}
	l := listenlist.Front()
	for l != nil {
		v := l.Value.(*ConnectInfo)
		if v.Active && !strings.Contains(conns, v.NodeId) {
			err := BoradcastSend(peerid, data, v)
			if err != nil {
				fmt.Println("BoradcastAllConn:", err)
			}
			conns = conns + "," + v.NodeId
		}
		l = l.Next()
	}
}
